<?php

namespace backend\controllers;

use Yii;
use backend\models\Queues;
use backend\models\Memberinfos;
use yii\data\ActiveDataProvider;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;

/**
 * QueueController implements the CRUD actions for Queues model.
 */
class QueuesController extends PublicController
{
    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'actions' => ['login'],
                        'allow' => true,
                    ],
                    [//认证过的用户允许访问的action
                        'actions' => ['index', 'view', 'queue-list', 'call', 'stat', 'stat-data'],
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
//                    'create' => ['post'],
//                    'update' => ['post'],
                ],
            ],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function actions()
    {
        return [
            'error' => [
                'class' => 'yii\web\ErrorAction',
            ],
        ];
    }

    /**
     * Lists all Queues models.
     * @return mixed
     */
    public function actionQueueList()
    {
        
        $find = Yii::$app->request->get('find');
        $start = Yii::$app->request->get('start');
        $end = Yii::$app->request->get('end');
        if(!empty($find) && $find != 'all'){
            $days = $this->getFindDays($find);
        }elseif(!empty($start) && !empty($end)){
            $days = $this->getDays($start, $end);
        }
        if($find == 'all'){
            $where = '1';
        }else{
            $where = empty($days) ? 'queueId=0' : ['inData' => $days];
        }
        $dataProvider = new ActiveDataProvider(['query' => Queues::find()->select('q.*, m.realName, m.idCardNo')->from('{{%queues}} as q')->leftJoin('{{%memberinfos}} as m', 'm.memberKey = q.memberKey')->where($where)]);
        $burl = explode('?', $_SERVER['REQUEST_URI']);
        return $this->render('queue-list', [
            'dataProvider' => $dataProvider,
            'baseurl' => $burl[0],
            'find' => $find,
            'start' => $start,
            'end' => $end
        ]);
    }

    private function getDays($start, $end){
        $start = strtotime($start);
        $end = strtotime($end);
        $days = [];
        for($i = $start; $i <= $end; $i += 86400) {
            $days[] = date('Y-m-d', $i);
        }
        return $days;
    }

    private function getFindDays($find){
        switch($find){
            case '':
                $days = '';
            break;
            case 'today':
                $days = date('Y-m-d');
            break;
            case 'yesterday':
                $days = date('Y-m-d', time() - 86400);
            break;
            case 'thisweek':
                $days = $this->getWeekDays('this');
            break;
            case 'lastweek':
                $days = $this->getWeekDays('last');
            break;
            case 'thismonth':
                $days = $this->getMonthDays('this');
            break;
            case 'lastmonth':
                $days = $this->getMonthDays('last');
            break;
        }
        return $days;
    }

    private function getWeekDays($type){
        if($type == 'this'){
            $baseday = time();
        }elseif($type == 'last'){
            $baseday = time() - 86400 * 7;
        }
        $weekNum = date("w", $baseday);
        $start = $baseday - $weekNum * 86400;
        $end = $baseday + (7 - $weekNum) * 86400;
        $days = [];
        for($i = $start; $i < $end; $i += 86400){
            $days[] = date('Y-m-d', $i);
        }
        return $days;
    }

    private function getMonthDays($type){
        if($type == 'this'){
            $year = date('Y');
            $month = date('m');
        }elseif($type == 'last'){
            $month = date('m');
            if($month == 1){
                $year = date('Y') - 1;
                $month = 12;
            }else{
                $year = date('Y');
                $month = date('m') - 1;
            }
        }
        $endDay = $this->getMonthDay($year, $month);
        $days = [];
        for($i = 1; $i <= $endDay; $i++){
            $days[] = $year.'-'.$month.'-'.$i;
        }
        return $days;
    }

    

    /**
     * Displays a single Queues model.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionStat(){
        return $this->render('stat');
    }

    
    //今日，本周，本月的数据是动态的所以需要使用计算来获取
    //往日统计数据应该以日为单位放在统计表中
    //周和月的统计数据可以在日数据中心做循环加获得
    public function actionStatData(){
        $type = Yii::$app->request->post('type');
        if(empty($type)){
            $type = 'day';
        }
        switch($type){
            case 'day':
                $data = $this->getStatDay();
            break;
            case 'week':
                $data = $this->getStatWeek();
            break;
            case 'month':
                $data = $this->getStatMonth();
            break;
            case 'year':
                $data = $this->getStatYear();
            break;
        }
        $this->renderJson($data);
        return $data;
    }

    private function getStatYear(){
        $section = $this->getYearSection();
        $dataQueued = Queues::yearQueueStat($section);
        $dataIn = Queues::yearInStat($section);
        $dataPass = Queues::yearPassStat($section);
        $inRates = $this->InRate($dataQueued, $dataIn);
        $passRates = $this->PassRate($dataQueued, $dataPass);
        return ['labels' => $section, 'dataQueued' => $dataQueued, 'dataIn' => $dataIn, 'dataPass' => $dataPass, 'inRates' => $inRates, 'passRates' => $passRates];
    }

    private function getYearSection(){
        $len = $this->setting('year_stat_length');
        $year = date('Y');
        $years = [];
        for($i = 0; $i < $len; $i++){
            $years[] = $year - $i;
        }
        return $years;
    }



    private function getStatMonth(){
        $sectionNames = $this->getMonthSection();
        $section = $this->getUseMonthSection($sectionNames);
        $dataQueued = Queues::QueueStat($section);
        $dataIn = Queues::InStat($section);
        $dataPass = Queues::PassStat($section);
        $inRates = $this->inRate($dataQueued, $dataIn);
        $passRates = $this->passRate($dataQueued, $dataPass);
        return ['labels' => $sectionNames, 'dataQueued' => $dataQueued, 'dataIn' => $dataIn, 'dataPass' => $dataPass, 'inRates' => $inRates, 'passRates' => $passRates];
    }

    private function getUseMonthSection($section){
        $sectionArray = [];
        foreach($section as $k => $v){
            $vs = explode('-', $v);
            $dayTotal = $this->getMonthDay($vs[0], $vs[1]);
            for($i = 1; $i <= $dayTotal; $i++){
                $sectionArray[$k][] = $v.'-'.$i;
            }
        }
        return $sectionArray;
    }

    private function getMonthSection(){
        $len = $this->setting('month_stat_length');
        $year = date('Y');
        $month = date('m');
        $months = [];
        for($i = 0; $i < $len; $i++){
            $m = $month - $i;
            $y = $year;
            if($m <= 0){
                $m += 12;
                $y = $year - 1;
            }
            $ms = ($m < 10) ? '0'.$m : $m;
            $months[] = $y.'-'.$ms;
        }
        return $months;
    }

    private function getStatWeek(){
        $section = $this->getWeekSection();
        $dataQueued = Queues::QueueStat($section);
        $dataIn = Queues::InStat($section);
        $dataPass = Queues::PassStat($section);
        $inRates = $this->inRate($dataQueued, $dataIn);
        $passRates = $this->passRate($dataQueued, $dataPass);
        return ['labels' => $this->getDisplaySection($section), 'dataQueued' => $dataQueued, 'dataIn' => $dataIn, 'dataPass' => $dataPass, 'inRates' => $inRates, 'passRates' => $passRates];
    }

    private function getDisplaySection($section){
        $displaySection = [];
        foreach($section as $k => $v){
            $last = count($v) - 1;
            $displaySection[] = $v[0].' - '. $v[$last];
        }
        return $displaySection;
    }

    private function getWeekSection(){
        $len = $this->setting('week_stat_length');
        $thisweek = $this->getWeekDays('this');
        for($i = $len; $i > 0; $i--){
            $week = [];
            foreach($thisweek as $k => $v){
                $week[] = date('Y-m-d', strtotime($v) - $i * 7 * 86400);
            }
            $weeks[] = $week;
        }
        $weeks[] = $thisweek;
        return array_reverse($weeks);
    }

    private function getStatDay(){
        $section = $this->getDaySection();
        $dataQueued = Queues::dayQueueStat($section);
        $dataIn = Queues::dayInStat($section);
        $dataPass = Queues::dayPassStat($section);
        $inRates = $this->inRate($dataQueued, $dataIn);
        $passRates = $this->passRate($dataQueued, $dataPass);
        return ['labels' => $section, 'dataQueued' => $dataQueued, 'dataIn' => $dataIn, 'dataPass' => $dataPass, 'inRates' => $inRates, 'passRates' => $passRates];
    }

    private function passRate($dataQueued, $dataPass){
        $d = [];
        foreach($dataQueued as $k => $v){
            $d[] = $v == 0 ? 0 : round(($dataPass[$k] / $v) * 100, 2);
        }
        return $d;
    }

    private function inRate($dataQueued, $dataIn){
        $d = [];
        foreach($dataQueued as $k => $v){
            $d[] = $v == 0 ? 0 : round(($dataIn[$k] / $v) * 100, 2);
        }
        return $d;
    }


    private function getDaySection(){
        $len = $this->setting('day_stat_length');
        if($len == 'max'){
            $year = date('Y');
            $month = date('m');
            if($month == 1){
                $month = 12;
                $year -= 1;
            }elseif($month > 1){
                $month -= 1;
            }
            $len = $this->getMonthDay($year, $month);
        }
        $time = time();
        $section = [];
        for($i = $time; $i > $time - $len * 86400; $i -= 86400){
            $section[] = date('Y-m-d', $i);
        }
        return $section;
    }

    private function getMonthDay($year, $month){
        if(in_array($month, [1,3,5,7,8,10,12])){
            $len = 31;
        }elseif(in_array($month, [4,6,9,11])){
            $len = 30;
        }else{
            $len = $year % 4 == 0 && $year % 400 != 0 ? 29 : 28;
        }
        return $len;
    }

    /**
     * Displays a single Queues model.
     * @param integer $id
     * @return mixed
     * @throws NotFoundHttpException if the model cannot be found
     */
    public function actionView($id)
    {
        $model = $this->findModel($id);
        $m = Memberinfos::findOne(['memberKey' => $model->memberKey]);
        $model->realName = $m->realName;
        $model->idCardNo = $m->idCardNo;
        return $this->render('view', [
            'model' => $model,
        ]);
    }

    public function actionCall(){
        $cacheKey = 'call_list';
        $total = Yii::$app->request->post('total');
        if(empty($total)){
            $total = 1;
        }
        $data = [
            'todayQueueNumber' => Queues::todayQueueNumber(date('Y-m-d')),
            'currentQueueNumber' => Queues::currentQueueNumber(date('Y-m-d')),
            'todayCallNumber' => Queues::todayCallNumber(date('Y-m-d')),
            'todayPassNumber' => Queues::todayPassNumber(date('Y-m-d')),
            'todayInNumber' => Queues::todayInNumber(date('Y-m-d'))
        ];
        $result = $this->queuePass($cacheKey);//过号处理
        $res = $this->call($total, $cacheKey);//执行叫号
        if($res == 'empty'){
            return $this->renderJson(['code' => 1, 'result' => ['result' => false, 'data' => $data], 'msg' => '队列为空，暂无人排队', 'errorCode' => 0]);
        }elseif($res == false){
            return $this->renderJson(['code' => 0, 'result' => ['result' => false], 'msg' => '叫号失败，请与管理员联系', 'errorCode' => 100002]);
        }
        return $this->renderJson(['code' => 1, 'result' => ['result' => true, 'data' => $data], 'msg' => '叫号成功', 'errorCode' => 0]);
    }

    /**
     * 执行叫号
     */
    private function call($total, $cacheKey){
        $queueKeys = [];
        $data = Queues::find()->where(['inData' => date('Y-m-d'), 'status' => 1, 'call' => 1])->orderBy('queueNumber ASC')->limit($total)->asArray()->all();
        if(empty($data)){
            return 'empty';
        }
        foreach((array)$data as $k => $v){
            $queueKeys[] = $v['queueKey'];
        }
        $this->redis->set($cacheKey, serialize($queueKeys));
        return Queues::updateAll(['call' => 2], ['queueKey' => $queueKeys]);
    }
    
    /**
     * 过号处理
     */
    private function queuePass($cacheKey){
        $list = unserialize($this->redis->get($cacheKey));
        if(empty($list)){
            $d = Queues::find()->where(['inData' => date('Y-m-d'), 'call' => 2])->asArray()->all();
            if(empty($d)){
                return true;
            }
            foreach((array)$d as $k => $v){
                $list[] = $v['queueKey'];
            }
            
        }
        $data = Queues::find()->where(['queueKey' => $list])->asArray()->all();
        $queueKeys = [];
        foreach((array)$data as $key => $value){
            if($value['call'] == 2 && $value['status'] == 1){
                $queueKeys[] = $value['queueKey'];
            }
        }
        $result = Queues::updateAll(['call' => 3, 'status' => 3], ['queueKey' => $queueKeys]);
        $this->redis->del($cacheKey);
        return true;
    }

    /**
     * Finds the Queues model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     * @param integer $id
     * @return Queues the loaded model
     * @throws NotFoundHttpException if the model cannot be found
     */
    protected function findModel($id)
    {
        if (($model = Queues::findOne($id)) !== null) {
            return $model;
        }

        throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
    }
}
